package com.atwisdom.star.dcs.service.Impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import com.atwisdom.star.dcs.dao.RealTimeInfoDayDao;
import com.atwisdom.star.dcs.dao.RealTimeInfoMinuteDao;
import com.atwisdom.star.dcs.pojo.RealTimeInfo;
import com.atwisdom.star.dcs.pojo.RealTimeInfoDay;
import com.atwisdom.star.dcs.pojo.RealTimeInfoMinute;
import com.atwisdom.star.dcs.service.RealTimeDayStatService;
import com.atwisdom.star.dcs.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class RealTimeDayStatServiceImpl implements RealTimeDayStatService {
    @Autowired
    private RealTimeInfoMinuteDao realTimeInfoMinuteDao;

    @Autowired
    private RealTimeInfoDayDao realTimeInfoDayDao;

    @Override
    public void realTimeDataStat() {
        long currentTimestamp = DateUtils.getMinuteTimestamp(System.currentTimeMillis());
        List<String> names = realTimeInfoMinuteDao.queryPointNames();
        for (String name : names) {
            //asc
            RealTimeInfoMinute timeInfoMinute = realTimeInfoMinuteDao.findOne("name=='" + name + "'",
                    "statTimestamp,asc");
            if (timeInfoMinute == null) {
                continue;
            }
            long startTimestamp = (timeInfoMinute.getStatTimestamp() / (60*60*24 * 1000)) * (60*60*24 * 1000);
            //desc
            RealTimeInfoDay timeInfoDay = realTimeInfoDayDao.findOne("name=='" + name + "'", "endTimestamp," +
                    "desc");
            if (timeInfoDay != null) {
                startTimestamp = timeInfoDay.getStatTimestamp();
                realTimeInfoDayDao.remove(timeInfoDay);
            }

            while (startTimestamp < currentTimestamp) {
                long endTimestamp = startTimestamp+60*60*24*1000; //结束时间戳到59分59秒
                String  condition = "name=='" + name + "'&& statTimestamp > '"+ startTimestamp +"'";
                //asc
                RealTimeInfoMinute  realTimeInfo = realTimeInfoMinuteDao.findOne(condition, "statTimestamp,asc");
                if (realTimeInfo == null) {
                    break;
                }
                buildRealTimeDayStat(name, startTimestamp, endTimestamp);
                startTimestamp = startTimestamp+1000*60*60*24;
            }
        }
    }

    private void buildRealTimeDayStat(String name, long startTimestamp, long endTimestamp) {
        //asc
        RealTimeInfoMinute startRealTimeInfo = realTimeInfoMinuteDao.findOne("name=='" + name + "' &&statTimestamp " +
                "between " +
                "'" + startTimestamp + "' and '" + endTimestamp + "'", "statTimestamp,asc");
        //desc
        RealTimeInfoMinute endRealTimeInfo = realTimeInfoMinuteDao.findOne("name=='" + name + "' &&statTimestamp " +
                "between " +
                "'" + startTimestamp + "' and '" + endTimestamp + "'", "statTimestamp,desc");
        if(endRealTimeInfo==null){
            return;
        }
        double diffPv = getDiffPv(name, startTimestamp, endTimestamp);
        RealTimeInfoDay realTimeInfo = buildRealTimeInfoStat(startTimestamp,diffPv, endRealTimeInfo, startRealTimeInfo);
        realTimeInfoDayDao.save(realTimeInfo);
    }

    private RealTimeInfoDay buildRealTimeInfoStat(long startTimestamp, Double diffPv, RealTimeInfoMinute nextRealTimeInfo, RealTimeInfoMinute preRealTimeInfo) {
        RealTimeInfoDay realTimeInfo = new RealTimeInfoDay();
        realTimeInfo.setCode(nextRealTimeInfo.getCode());
        realTimeInfo.setCategory(nextRealTimeInfo.getCategory());
        realTimeInfo.setPf(nextRealTimeInfo.getPf());
        realTimeInfo.setName(nextRealTimeInfo.getName());
        realTimeInfo.setPv(nextRealTimeInfo.getPv());
        realTimeInfo.setEndTimestamp(nextRealTimeInfo.getEndTimestamp());
        realTimeInfo.setStartTimestamp(startTimestamp);
        realTimeInfo.setStatTimestamp(startTimestamp);
        realTimeInfo.setDiffPv(diffPv);
        realTimeInfo.setDuration(nextRealTimeInfo.getEndTimestamp() - startTimestamp);
        if (preRealTimeInfo != null) {
            realTimeInfo.setLastPv(preRealTimeInfo.getPv());
        } else {
            realTimeInfo.setLastPv(nextRealTimeInfo.getLastPv());
        }
        return realTimeInfo;
    }

    private double getDiffPv(String name, long startTimestamp, long endTimestamp) {
        String condition = "name=='" + name + "' &&statTimestamp " +
                "between " +
                "'" + startTimestamp + "' and '" + endTimestamp + "'";
        List<RealTimeInfoMinute> infoMinutes  = realTimeInfoMinuteDao.query(condition);
        if(CollectionUtil.isNotEmpty(infoMinutes)){
            return infoMinutes.stream().mapToDouble(RealTimeInfoMinute::getDiffPv).sum();
        }else{
            return 0.0;
        }
    }


    /**
     * 计算生产节拍
     * @param equipCode 设备编码，pCode:品番，statDate：日期
     * @return 返回生产节拍
     */
    @Override
    public Double calculateCycleCount(String equipCode, Date statDate) {
        LocalDate localStatDate = DateUtils.ConvertDateToLocalDate(statDate);
        LocalDateTime startDateTime = DateUtils.getLocalDateTime(localStatDate, "00:00:00");
        LocalDateTime endDateTime= DateUtils.getLocalDateTime(localStatDate, "23:59:59");
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = startDateTime.toInstant(offset).toEpochMilli();
        long endTimestamp = endDateTime.toInstant(offset).toEpochMilli();

        String nameA = equipCode + RealTimeInfo.JS_MARK + "A";
        String nameB = equipCode + RealTimeInfo.JS_MARK + "B";
        String name = equipCode + RealTimeInfo.JS_MARK;
        double diffPv = 0.0;
        double duration = 0;

        String condition = "{\"code\":\"" + equipCode + "\",\"name\":\"" + name + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        List<RealTimeInfoDay> infoMinutes  = realTimeInfoDayDao.query(condition);
        if(CollectionUtil.isNotEmpty(infoMinutes)){
            diffPv += infoMinutes.stream().mapToDouble(RealTimeInfoDay::getDiffPv).sum();
            duration += infoMinutes.stream().mapToDouble(RealTimeInfoDay::getDuration).sum();
        }

        condition = "{\"code\":\"" + equipCode + "\",\"name\":\"" + nameA + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        infoMinutes  = realTimeInfoDayDao.query(condition);
        if(CollectionUtil.isNotEmpty(infoMinutes)){
            diffPv += infoMinutes.stream().mapToDouble(RealTimeInfoDay::getDiffPv).sum();
            duration += infoMinutes.stream().mapToDouble(RealTimeInfoDay::getDuration).sum();
        }

        condition = "{\"code\":\"" + equipCode + "\",\"name\":\"" + nameB + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        infoMinutes  = realTimeInfoDayDao.query(condition);
        if(CollectionUtil.isNotEmpty(infoMinutes)){
            diffPv += infoMinutes.stream().mapToDouble(RealTimeInfoDay::getDiffPv).sum();
            duration += infoMinutes.stream().mapToDouble(RealTimeInfoDay::getDuration).sum();
        }

        double minuteDuration = Math.floor(duration*100/(1000*60))/100.0;
        Double cycleCount;
        if(minuteDuration<1){
            cycleCount = 0.0;
        }else{
            cycleCount = Math.floor(diffPv*100/minuteDuration)/100.0;
        }
        return cycleCount;
    }


    /**
     * 按设备计数
     * @param equipCode 设备编码
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 返回计数统计
     */
    @Override
    public double getEquipCount(String equipCode, DateTime startTime, DateTime endTime){
        LocalDateTime localStartTime = DateUtils.hutoolDateTimeToLocalDateTime(startTime);
        LocalDateTime localEndTime = DateUtils.hutoolDateTimeToLocalDateTime(endTime);
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = localStartTime.toInstant(offset).toEpochMilli();
        long endTimestamp = localEndTime.toInstant(offset).toEpochMilli();
        double diffPv = 0.0;

        String condition = "{\"code\":\"" + equipCode + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        List<RealTimeInfoDay> timeInfoDays  = realTimeInfoDayDao.query(condition);
        if(CollectionUtil.isNotEmpty(timeInfoDays)){
            diffPv += timeInfoDays.stream().mapToDouble(RealTimeInfoDay::getDiffPv).sum();
        }
        return  diffPv;
    }

    /**
     * 按设备列表计数
     * @param equipCodes 设备编码列表
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 返回计数统计Map
     */
    @Override
    public Map<String,Double> queryEquipCount(List<String> equipCodes, DateTime startTime, DateTime endTime){
        LocalDateTime localStartTime = DateUtils.hutoolDateTimeToLocalDateTime(startTime);
        LocalDateTime localEndTime = DateUtils.hutoolDateTimeToLocalDateTime(endTime);
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = localStartTime.toInstant(offset).toEpochMilli();
        long endTimestamp = localEndTime.toInstant(offset).toEpochMilli();
        Map<String,Double> equipMap = new HashMap<>();
        equipCodes.forEach(code->{
            double diffPv = 0.0;
            String condition = "{\"code\":\"" + code + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
            List<RealTimeInfoDay> timeInfoDays  = realTimeInfoDayDao.query(condition);
            if(CollectionUtil.isNotEmpty(timeInfoDays)){
                diffPv += timeInfoDays.stream().mapToDouble(RealTimeInfoDay::getDiffPv).sum();
                equipMap.put(code,diffPv);
            }
        });
        return  equipMap;
    }

    /**
     *按设备品番计数
     * @param equipCode 设备编码
     * @param pCode 产品品番编号
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 返回计数统计
     * @return
     */
    @Override
    public double getEquipPfCount(String equipCode,String pCode, DateTime startTime,DateTime endTime){
        LocalDateTime localStartTime = DateUtils.hutoolDateTimeToLocalDateTime(startTime);
        LocalDateTime localEndTime = DateUtils.hutoolDateTimeToLocalDateTime(endTime);
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = localStartTime.toInstant(offset).toEpochMilli();
        long endTimestamp = localEndTime.toInstant(offset).toEpochMilli();
        double diffPv = 0.0;

        String condition = "{\"code\":\"" + equipCode + "\",\"pf\":\"" + pCode + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        List<RealTimeInfoDay> timeInfoDays  = realTimeInfoDayDao.query(condition);
        if(CollectionUtil.isNotEmpty(timeInfoDays)){
            diffPv += timeInfoDays.stream().mapToDouble(RealTimeInfoDay::getDiffPv).sum();
        }
        return  diffPv;
    }



    /**
     * 设备有效工作时长
     * @param equipCode 设备编码
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 返回计数时长
     */
    @Override
    public double getEquipWorkDuration(String equipCode, DateTime startTime, DateTime endTime){
        LocalDateTime localStartTime = DateUtils.hutoolDateTimeToLocalDateTime(startTime);
        LocalDateTime localEndTime = DateUtils.hutoolDateTimeToLocalDateTime(endTime);
        ZoneOffset offset = ZoneOffset.ofHours(8);
        long startTimestamp = localStartTime.toInstant(offset).toEpochMilli();
        long endTimestamp = localEndTime.toInstant(offset).toEpochMilli();
        double duration = 0;
        String condition = "{\"code\":\"" + equipCode + "\",\"statTimestamp\":{$gte:" + startTimestamp + ",$lt:" + endTimestamp + "}}";
        List<RealTimeInfoDay> timeInfoDays  = realTimeInfoDayDao.query(condition);
        if(CollectionUtil.isNotEmpty(timeInfoDays)){
            duration += timeInfoDays.stream().mapToDouble(RealTimeInfoDay::getDuration).sum();
        }
        return  duration;
    }
}
